/********************************************************
* filename : pif2tms.c					*
* startdate : Fri, December 11 2009			*
* lastupdate : Thu, October 15 2010			*
* author : Limthong K. Kriangkrai			*
* location : NII Tokyo, Japan				*
*							*
* Convert a packet info file to a time series file	*
********************************************************/

#include <stdio.h>
//#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <ctype.h>

#define M_FLOW 65536 //Maximum flow in a second.
#define MAXLINE 300 //Maximum line of data in the packet info file.
#define MAXADDR 65536 //Maximum IP address in a second.
#define MAXPORT 65536 //Maximum port in a second.
#define N_ADDR 4 //Number of network address conversed from real IP address to new address, 4 mean not change.

struct flowtable {
	char saddr[16];
	char daddr[16];
	int sport;
	int dport;
} flowtable[M_FLOW];
int currentrowofflowtable = 0;

void clearflowtable();
int isinflowtable(char[16], char[16], int, int);

struct gsaddr {
        char saddr[16];
        unsigned count;
} gsaddr[MAXADDR];
int  next_gsaddr = 0;
int isingsaddr(char[16]);

struct gdaddr {
	char daddr[16];
	unsigned count;
} gdaddr[MAXADDR];
int  next_gdaddr = 0;
int isingdaddr(char[16]);

struct gsport {
	unsigned sport;
	unsigned count;
} gsport[MAXPORT];
int next_gsport = 0;
int isingsport(unsigned);

struct gdport {
	unsigned dport;
	unsigned count;
} gdport[MAXPORT];
int next_gdport = 0;
int isingdport(unsigned);

char *convertaddr(char addr[16], int);
char newaddr[16];

int main(int argc, char *argv[]) {
	//To check arguments.
	char *ofile = NULL;
	int interval = 1;

	int c;
	opterr = 0;

	if(argc < 2) {
		printf("Usage: %s PIFFILE [OPTION]\n", argv[0]);
		printf("Convert a packet info file to a time series file\n\n");
		printf("  -o FILE write output to FILE.\n");
		printf("  -s NUM set sampling interval to NUM second (default 1).\n\n");
		printf("Report bugs to <krngkr@nii.ac.jp>.\n");
		return 1;
	}
	char *piffile = argv[1];
	while((c = getopt(argc, argv, "o:s:")) != -1)
		switch(c) {
			case 'o':
				ofile = optarg;
				break;
			case 's':
				interval = atoi(optarg);
				break;
			case '?':
				if(optopt == 'o' || optopt == 's')
					fprintf(stderr, "Option -%c requires an argument.\n", optopt);
				else if(isprint(optopt))
					fprintf(stderr, "Unknown option `-%c'.\n", optopt);
				else
					fprintf(stderr, "Unknown option character `\\x%x'.\n", optopt);
				return 1;
		}
	//To check file existing.
	FILE *testFile;
	testFile = fopen(piffile, "r");
	if(testFile == NULL) {
		perror ("pif2tms");
		return 1;
	}
	//End check arguments.

	char *tmsfile = ofile;
	if(tmsfile != NULL) printf("%s > %s\n", piffile, tmsfile);

	char *packettime;
	int timestamp;
	char saddr[16], daddr[16];
	int sport, dport;
	int packetsize;
	int EDTflag = 0;

	int count = 0, size = 0, flow = 0;

	int columnindex;
	char referencepackettime[20];
	int referencetimestamp = 0;
	int firstpacket = 0;

	//Read a packet information file.
	char line[MAXLINE];
	char *sub_string;
	FILE *pFile, *tFile;
	if(tmsfile != NULL) tFile = fopen(tmsfile,"w");//Open the time series file.
	if((pFile = fopen(piffile, "r")) != NULL) {//Open the packet info file for read data.
		while(fgets(line, MAXLINE, pFile) != NULL) {
			packettime = strtok(line, ",");
			//printf("%s, \n", packettime);
			columnindex = 0;
			while((sub_string = strtok(NULL, " \t\n")) != NULL) {
				switch(columnindex) {
					case 0:
						timestamp = atoi(sub_string)/interval;
						//printf("%d\t", timestamp);
						if(strstr(packettime,"EDT") != NULL && timestamp == referencetimestamp) EDTflag = 1;//Check EDT in packettime.
						break;
					case 1:
						strcpy(saddr,sub_string);
						//printf("%s ", saddr);
						break;
					case 2:
						strcpy(daddr,sub_string);
						//printf("%s ", daddr);
						break;
					case 3:
						sport = atoi(sub_string);
						//printf("%d ", sport);
						break;
					case 4:
						dport = atoi(sub_string);
						//printf("%d ", dport);
						break;
					case 5:
						packetsize = atoi(sub_string);
						//printf("%d\n", packetsize);
						break;
				}
			columnindex++;
			}
			//printf("#%s, %d\t%s %s %d %d %d\n", packettime, timestamp, saddr, daddr, sport, dport, packetsize);
			//printf("#%s, %d\n", packettime, timestamp);
			if(timestamp == referencetimestamp) {
				if(referencetimestamp == 0 && firstpacket == 0) {
					strcpy(referencepackettime,packettime);
					firstpacket++;
				}

				isingsaddr(convertaddr(saddr,N_ADDR)); isingdaddr(convertaddr(daddr,N_ADDR));
				isingsport(sport); isingdport(dport);

				count++; size+=packetsize;
				flow+=isinflowtable(saddr, daddr, sport, dport);
				//printf("%s, %d\t%s %s %d %d %d\n", packettime, timestamp, saddr, daddr, sport, dport, packetsize);

			} else if (timestamp > referencetimestamp) {
				if(referencetimestamp == 0 && firstpacket == 1) {
					if(EDTflag == 1 && strstr(referencepackettime,"EDT") == NULL)//Check EDTflag and change ICT to EDT.
						strncpy(strstr(referencepackettime,"ICT"), "EDT", 3);
					if(tmsfile == NULL) printf("%s, %d\t%d %d %d %d %d %d %d %d %d\n", referencepackettime, referencetimestamp, count, size, flow, next_gsaddr, next_gdaddr, next_gsport, next_gdport, abs(next_gsaddr-next_gdaddr), abs(next_gsport-next_gdport));
				} else if(referencetimestamp != 0) {
					if(EDTflag == 1 && strstr(referencepackettime,"EDT") == NULL)//Check EDTflag and change ICT to EDT.
						strncpy(strstr(referencepackettime,"ICT"), "EDT", 3);
					if(tmsfile == NULL) printf("%s, %d\t%d %d %d %d %d %d %d %d %d\n", referencepackettime, referencetimestamp, count, size, flow, next_gsaddr, next_gdaddr, next_gsport, next_gdport, abs(next_gsaddr-next_gdaddr), abs(next_gsport-next_gdport));
					else fprintf(tFile, "%s, %d\t%d %d %d %d %d %d %d %d %d\n", referencepackettime, referencetimestamp, count, size, flow, next_gsaddr, next_gdaddr, next_gsport, next_gdport, abs(next_gsaddr-next_gdaddr), abs(next_gsport-next_gdport));
				}

				count = 0; size = 0; flow = 0; next_gsaddr = 0; next_gdaddr = 0; next_gsport = 0; next_gdport = 0;//Reset the values.
				clearflowtable();
				EDTflag = 0;

				strcpy(referencepackettime,packettime);
				referencetimestamp = timestamp;

				isingsaddr(convertaddr(saddr,N_ADDR)); isingdaddr(convertaddr(daddr,N_ADDR));
				isingsport(sport); isingdport(dport);

				count++; size+=packetsize;
				flow+=isinflowtable(saddr, daddr, sport, dport);
				//printf("%s, %d\t%s %s %d %d %d\n", packettime, timestamp, saddr, daddr, sport, dport, packetsize);
			}
		}
		if(EDTflag == 1 && strstr(referencepackettime,"EDT") == NULL)//Check EDTflag and change ICT to EDT.
			strncpy(strstr(referencepackettime,"ICT"), "EDT", 3);
		if(tmsfile == NULL) printf("%s, %d\t%d %d %d %d %d %d %d %d %d\n", referencepackettime, referencetimestamp, count, size, flow, next_gsaddr, next_gdaddr, next_gsport, next_gdport, abs(next_gsaddr-next_gdaddr), abs(next_gsport-next_gdport));//Printing the last packet.
		else fprintf(tFile, "%s, %d\t%d %d %d %d %d %d %d %d %d\n", referencepackettime, referencetimestamp, count, size, flow, next_gsaddr, next_gdaddr, next_gsport, next_gdport, abs(next_gsaddr-next_gdaddr), abs(next_gsport-next_gdport));//Printing the last packet.
	}
	fclose(pFile);//Close the packet information file.
	if(tmsfile != NULL) fclose(tFile);//Close the time series file.
	return 0;
}

void clearflowtable() {
	currentrowofflowtable = 0;
	strcpy(flowtable[currentrowofflowtable].saddr,"0.0.0.0");
	strcpy(flowtable[currentrowofflowtable].daddr,"0.0.0.0");
	flowtable[currentrowofflowtable].sport = 0;
	flowtable[currentrowofflowtable].dport = 0;
}

int isinflowtable(char saddr[16], char daddr[16], int sport, int dport) {
	int i;
	for(i = 0; i < currentrowofflowtable; i++) {
		//The following 3 lines are the flow rules. Please choose only 1 line.
		//if(strcmp(saddr,flowtable[i].saddr) == 0 && strcmp(daddr,flowtable[i].daddr) == 0) return 0;
		//if(strcmp(sport == flowtable[i].sport && dport == flowtable[i].dport) return 0;
		if(strcmp(saddr,flowtable[i].saddr) == 0 && strcmp(daddr,flowtable[i].daddr) == 0 && sport == flowtable[i].sport && dport == flowtable[i].dport) return 0;
	}
	strcpy(flowtable[currentrowofflowtable].saddr,saddr); strcpy(flowtable[currentrowofflowtable].daddr,daddr);
	flowtable[currentrowofflowtable].sport = sport; flowtable[currentrowofflowtable].dport = dport;
	currentrowofflowtable++;
	return 1;
}

int isingsaddr(char saddr[16]) {
        int i, j;
        char saddrtemp[16];
        unsigned counttemp;
        for(i = 0; i < next_gsaddr; i++) {
                if(strcmp(saddr,gsaddr[i].saddr) == 0) {
                        gsaddr[i].count++;
                        for(j = i; j > 0; j--) { //Sort maximum count on the top.
                                if(gsaddr[j].count > gsaddr[j-1].count) {
                                        strcpy(saddrtemp,gsaddr[j-1].saddr); counttemp = gsaddr[j-1].count;
                                        strcpy(gsaddr[j-1].saddr,gsaddr[j].saddr); gsaddr[j-1].count = gsaddr[j].count;
                                        strcpy(gsaddr[j].saddr,saddrtemp); gsaddr[j].count = counttemp;
                                }
                        }
                        return 1;
                }
        }
        strcpy(gsaddr[next_gsaddr].saddr,saddr);
        gsaddr[next_gsaddr].count = 1;
        next_gsaddr++;
        return 0;
}

int isingdaddr(char daddr[16]) {
	int i, j;
	char daddrtemp[16];
	unsigned counttemp;
	for(i = 0; i < next_gdaddr; i++) {
		if(strcmp(daddr,gdaddr[i].daddr) == 0) {
			gdaddr[i].count++;
			for(j = i; j > 0; j--) {
				if(gdaddr[j].count > gdaddr[j-1].count) {
					strcpy(daddrtemp,gdaddr[j-1].daddr); counttemp = gdaddr[j-1].count;
					strcpy(gdaddr[j-1].daddr,gdaddr[j].daddr); gdaddr[j-1].count = gdaddr[j].count;
					strcpy(gdaddr[j].daddr,daddrtemp); gdaddr[j].count = counttemp;
				}
			}
			return 1;
		}
	}
	strcpy(gdaddr[next_gdaddr].daddr,daddr);
	gdaddr[next_gdaddr].count = 1;
	next_gdaddr++;
	return 0;
}

int isingsport(unsigned sport) {
	int i, j;
	unsigned sporttemp, counttemp;
	for(i = 0; i < next_gsport; i++) {
		if(gsport[i].sport == sport) {
			gsport[i].count++;
			for(j = i; j > 0; j--) {
				if(gsport[j].count > gsport[j-1].count) {
					sporttemp = gsport[j-1].sport; counttemp = gsport[j-1].count;
					gsport[j-1].sport = gsport[j].sport; gsport[j-1].count = gsport[j].count;
					gsport[j].sport = sporttemp; gsport[j].count = counttemp;
				}
			}
			return 1;
		}
	}
	gsport[next_gsport].sport = sport;
	gsport[next_gsport].count = 1;
	next_gsport++;
	return 0;
}

int isingdport(unsigned dport) {
	int i, j;
	unsigned dporttemp, counttemp;
	for(i = 0; i < next_gdport; i++) {
		if(gdport[i].dport == dport) {
			gdport[i].count++;
			for(j = i; j > 0; j--) {
				if(gdport[j].count > gdport[j-1].count) {
					dporttemp = gdport[j-1].dport; counttemp = gdport[j-1].count;
					gdport[j-1].dport = gdport[j].dport; gdport[j-1].count = gdport[j].count;
					gdport[j].dport = dporttemp; gdport[j].count = counttemp;
				}
			}
			return 1;
		}
	}
	gdport[next_gdport].dport = dport;
	gdport[next_gdport].count = 1;
	next_gdport++;
	return 0;
}

char *convertaddr(char addr[16], int n) {
        char temp[16];
        char *addr1, *addr2, *addr3, *addr4;
        strcpy(temp, addr);
        addr1 = strtok(temp, ".");
        addr2 = strtok(NULL, ".");
        addr3 = strtok(NULL, ".");
        addr4 = strtok(NULL, ".");

	switch(n) {
		case 1:
			strcpy(newaddr, addr1);
			strcat(newaddr, ".0.0.0");
			return(newaddr);
			break;
		case 2:
			strcpy(newaddr, addr1);
			strcat(newaddr, ".");
			strcat(newaddr, addr2);
			strcat(newaddr, ".0.0");
			return(newaddr);
			break;
		case 3:
			strcpy(newaddr, addr1);
			strcat(newaddr, ".");
			strcat(newaddr, addr2);
			strcat(newaddr, ".");
			strcat(newaddr, addr3);
			strcat(newaddr, ".0");
			return(newaddr);
			break;
		default:
			return (addr);
			break;
	}
}
